<!DOCTYPE html>
<html lang="en-us">
  <head>

    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    
<meta charset="UTF-8">
<title>Denormalization and Concurrency | Elasticsearch: The Definitive Guide [2.x] | Elastic</title>
<link rel="home" href="index.html" title="Elasticsearch: The Definitive Guide [2.x]">
<link rel="up" href="relations.html" title="Handling Relationships">
<link rel="prev" href="top-hits.html" title="Field Collapsing">
<link rel="next" href="concurrency-solutions.html" title="Solving Concurrency Issues">
<meta name="DC.type" content="Learn/Docs/Legacy/Elasticsearch/Definitive Guide/2.x">
<meta name="DC.subject" content="Elasticsearch">
<meta name="DC.identifier" content="2.x">
<meta name="robots" content="noindex,nofollow">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://cdn.optimizely.com/js/18132920325.js"></script>
    <link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png">
    <link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png">
    <link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png">
    <link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png">
    <link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png">
    <link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png">
    <link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png">
    <link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png">
    <link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png">
    <link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32">
    <link rel="icon" type="image/png" href="/android-chrome-192x192.png" sizes="192x192">
    <link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96">
    <link rel="icon" type="image/png" href="/favicon-16x16.png" sizes="16x16">
    <link rel="manifest" href="/manifest.json">
    <meta name="apple-mobile-web-app-title" content="Elastic">
    <meta name="application-name" content="Elastic">
    <meta name="msapplication-TileColor" content="#ffffff">
    <meta name="msapplication-TileImage" content="/mstile-144x144.png">
    <meta name="theme-color" content="#ffffff">
    <meta name="naver-site-verification" content="936882c1853b701b3cef3721758d80535413dbfd">
    <meta name="yandex-verification" content="d8a47e95d0972434">
    <meta name="localized" content="true">
    <meta name="st:robots" content="follow,index">
    <meta property="og:image" content="https://www.elastic.co/static/images/elastic-logo-200.png">
    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
    <link rel="icon" href="/favicon.ico" type="image/x-icon">
    <link rel="apple-touch-icon-precomposed" sizes="64x64" href="/favicon_64x64_16bit.png">
    <link rel="apple-touch-icon-precomposed" sizes="32x32" href="/favicon_32x32.png">
    <link rel="apple-touch-icon-precomposed" sizes="16x16" href="/favicon_16x16.png">
    <!-- Give IE8 a fighting chance -->
    <!--[if lt IE 9]>
    <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
    <link rel="stylesheet" type="text/css" href="/guide/static/styles.css">
  </head>

  <!--© 2015-2021 Elasticsearch B.V. Copying, publishing and/or distributing without written permission is strictly prohibited.-->

  <body>
    <!-- Google Tag Manager -->
    <script>dataLayer = [];</script><noscript><iframe src="//www.googletagmanager.com/ns.html?id=GTM-58RLH5" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
    <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= '//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); })(window,document,'script','dataLayer','GTM-58RLH5');</script>
    <!-- End Google Tag Manager -->

    <!-- Global site tag (gtag.js) - Google Analytics -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-12395217-16"></script>
    <script>
      window.dataLayer = window.dataLayer || [];
      function gtag(){dataLayer.push(arguments);}
      gtag('js', new Date());
      gtag('config', 'UA-12395217-16');
    </script>

    <!--BEGIN QUALTRICS WEBSITE FEEDBACK SNIPPET-->
    <script type="text/javascript">
      (function(){var g=function(e,h,f,g){
      this.get=function(a){for(var a=a+"=",c=document.cookie.split(";"),b=0,e=c.length;b<e;b++){for(var d=c[b];" "==d.charAt(0);)d=d.substring(1,d.length);if(0==d.indexOf(a))return d.substring(a.length,d.length)}return null};
      this.set=function(a,c){var b="",b=new Date;b.setTime(b.getTime()+6048E5);b="; expires="+b.toGMTString();document.cookie=a+"="+c+b+"; path=/; "};
      this.check=function(){var a=this.get(f);if(a)a=a.split(":");else if(100!=e)"v"==h&&(e=Math.random()>=e/100?0:100),a=[h,e,0],this.set(f,a.join(":"));else return!0;var c=a[1];if(100==c)return!0;switch(a[0]){case "v":return!1;case "r":return c=a[2]%Math.floor(100/c),a[2]++,this.set(f,a.join(":")),!c}return!0};
      this.go=function(){if(this.check()){var a=document.createElement("script");a.type="text/javascript";a.src=g;document.body&&document.body.appendChild(a)}};
      this.start=function(){var a=this;window.addEventListener?window.addEventListener("load",function(){a.go()},!1):window.attachEvent&&window.attachEvent("onload",function(){a.go()})}};
      try{(new g(100,"r","QSI_S_ZN_emkP0oSe9Qrn7kF","https://znemkp0ose9qrn7kf-elastic.siteintercept.qualtrics.com/WRSiteInterceptEngine/?Q_ZID=ZN_emkP0oSe9Qrn7kF")).start()}catch(i){}})();
    </script><div id="ZN_emkP0oSe9Qrn7kF"><!--DO NOT REMOVE-CONTENTS PLACED HERE--></div>
    <!--END WEBSITE FEEDBACK SNIPPET-->

    <div id="elastic-nav" style="display:none;"></div>
    <script src="https://www.elastic.co/elastic-nav.js"></script>

    <!-- Subnav -->
    <div>
      <div>
        <div class="tertiary-nav d-none d-md-block">
          <div class="container">
            <div class="p-t-b-15 d-flex justify-content-between nav-container">
              <div class="breadcrum-wrapper"><span><a href="/guide/" style="font-size: 14px; font-weight: 600; color: #000;">Docs</a></span></div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <div class="main-container">
      <section id="content">
        <div class="content-wrapper">

          <section id="guide" lang="en">
            <div class="container">
              <div class="row">
                <div class="col-xs-12 col-sm-8 col-md-8 guide-section">
                  <!-- start body -->
                  <div class="page_header">
<p>
  <strong>WARNING</strong>: The 2.x versions of Elasticsearch have passed their
  <a href="https://www.elastic.co/support/eol">EOL dates</a>. If you are running
  a 2.x version, we strongly advise you to upgrade.
</p>
<p>
  This documentation is no longer maintained and may be removed. For the latest
  information, see the <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html">current
  Elasticsearch documentation</a>.
</p>
</div>
<div id="content">
<div class="breadcrumbs">
<span class="breadcrumb-link"><a href="index.html">Elasticsearch: The Definitive Guide [2.x]</a></span>
»
<span class="breadcrumb-link"><a href="modeling-your-data.html">Modeling Your Data</a></span>
»
<span class="breadcrumb-link"><a href="relations.html">Handling Relationships</a></span>
»
<span class="breadcrumb-node">Denormalization and Concurrency</span>
</div>
<div class="navheader">
<span class="prev">
<a href="top-hits.html">« Field Collapsing</a>
</span>
<span class="next">
<a href="concurrency-solutions.html">Solving Concurrency Issues »</a>
</span>
</div>
<div class="section">
<div class="titlepage"><div><div>
<h2 class="title">
<a id="denormalization-concurrency"></a>Denormalization and Concurrency<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch-definitive-guide/edit/2.x/400_Relationships/25_Concurrency.asciidoc">edit</a>
</h2>
</div></div></div>
<p>Of course, data denormalization has downsides too.  The first disadvantage is
that  the index will be bigger because the <code class="literal">_source</code> document for every
blog post is bigger, and there are more indexed fields.  This usually isn’t a
huge problem.  The data written to disk is highly compressed, and disk space
is cheap. Elasticsearch can happily cope with the extra data.</p>
<p>The more important issue is that, if the user were to change his name, all
of his blog posts would need to be updated too. Fortunately, users don’t
often change names.  Even if they did, it is unlikely that a user would have
written more than a few thousand blog posts, so updating blog posts with
the <a class="xref" href="scroll.html" title="Scroll"><code class="literal">scroll</code></a> and <a class="xref" href="bulk.html" title="Cheaper in Bulk"><code class="literal">bulk</code></a> APIs would take less than a
second.</p>
<p>However, let’s consider a more complex scenario in which changes are common, far
reaching, and, most important, concurrent.</p>
<p>In this example, we are going to emulate a filesystem with directory trees in
Elasticsearch, much like a filesystem on Linux: the root of the directory is
<code class="literal">/</code>, and each directory can contain files and subdirectories.</p>
<p>We want to be able to search for files that live in a particular directory,
the equivalent of this:</p>
<pre class="literallayout">grep "some text" /clinton/projects/elasticsearch/*</pre>

<p>This requires us to index the path of the directory where the file lives:</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">PUT /fs/file/1
{
  "name":     "README.txt", <a id="CO255-1"></a><i class="conum" data-value="1"></i>
  "path":     "/clinton/projects/elasticsearch", <a id="CO255-2"></a><i class="conum" data-value="2"></i>
  "contents": "Starting a new Elasticsearch project is easy..."
}</pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO255-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>The filename</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO255-2"><i class="conum" data-value="2"></i></a></p>
</td>
<td align="left" valign="top">
<p>The full path to the directory holding the file</p>
</td>
</tr>
</table>
</div>
<div class="note admon">
<div class="icon"></div>
<div class="admon_content">
<p>Really, we should also index <code class="literal">directory</code> documents so we can list all
files and subdirectories within a directory, but for brevity’s sake, we will
ignore that requirement.</p>
</div>
</div>
<p>We also want to be able to search for files that live anywhere in the
directory tree below a particular directory, the equivalent of this:</p>
<pre class="literallayout">grep -r "some text" /clinton</pre>

<p>To support this, we need to index the path hierarchy:</p>
<div class="ulist itemizedlist">
<ul class="itemizedlist">
<li class="listitem">
<code class="literal">/clinton</code>
</li>
<li class="listitem">
<code class="literal">/clinton/projects</code>
</li>
<li class="listitem">
<code class="literal">/clinton/projects/elasticsearch</code>
</li>
</ul>
</div>
<p>This hierarchy can be generated automatically from the <code class="literal">path</code> field using the
<a href="/guide/en/elasticsearch/reference/2.4/analysis-pathhierarchy-tokenizer.html" class="ulink" target="_top"><code class="literal">path_hierarchy</code> tokenizer</a>:</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">PUT /fs
{
  "settings": {
    "analysis": {
      "analyzer": {
        "paths": { <a id="CO256-1"></a><i class="conum" data-value="1"></i>
          "tokenizer": "path_hierarchy"
        }
      }
    }
  }
}</pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO256-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>The custom <code class="literal">paths</code> analyzer uses the <a href="/guide/en/elasticsearch/reference/2.4/analysis-pathhierarchy-tokenizer.html" class="ulink" target="_top"><code class="literal">path_hierarchy</code> tokenizer</a> with its default settings.</p>
</td>
</tr>
</table>
</div>
<p>The mapping for the <code class="literal">file</code> type would look like this:</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">PUT /fs/_mapping/file
{
  "properties": {
    "name": { <a id="CO257-1"></a><i class="conum" data-value="1"></i>
      "type":  "string",
      "index": "not_analyzed"
    },
    "path": { <a id="CO257-2"></a><i class="conum" data-value="2"></i>
      "type":  "string",
      "index": "not_analyzed",
      "fields": {
        "tree": { <a id="CO257-3"></a><i class="conum" data-value="2"></i>
          "type":     "string",
          "analyzer": "paths"
        }
      }
    }
  }
}</pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO257-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>The <code class="literal">name</code> field will contain the exact name.</p>
</td>
</tr>
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO257-2"><i class="conum" data-value="2"></i></a><a href="#CO257-3"></a></p>
</td>
<td align="left" valign="top">
<p>The <code class="literal">path</code> field will contain the exact directory name, while the <code class="literal">path.tree</code>
field will contain the path hierarchy.</p>
</td>
</tr>
</table>
</div>
<p>Once the index is set up and the files have been indexed, we can perform a
search for files containing <code class="literal">elasticsearch</code> in just the
<code class="literal">/clinton/projects/elasticsearch</code> directory like this:</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">GET /fs/file/_search
{
  "query": {
    "filtered": {
      "query": {
        "match": {
          "contents": "elasticsearch"
        }
      },
      "filter": {
        "term": { <a id="CO258-1"></a><i class="conum" data-value="1"></i>
          "path": "/clinton/projects/elasticsearch"
        }
      }
    }
  }
}</pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO258-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>Find files in this directory only.</p>
</td>
</tr>
</table>
</div>
<p>Every file that lives in any subdirectory under <code class="literal">/clinton</code> will include the
term <code class="literal">/clinton</code> in the <code class="literal">path.tree</code> field.  So we can search for all files in
any subdirectory of <code class="literal">/clinton</code> as follows:</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">GET /fs/file/_search
{
  "query": {
    "filtered": {
      "query": {
        "match": {
          "contents": "elasticsearch"
        }
      },
      "filter": {
        "term": { <a id="CO259-1"></a><i class="conum" data-value="1"></i>
          "path.tree": "/clinton"
        }
      }
    }
  }
}</pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO259-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>Find files in this directory or in any of its subdirectories.</p>
</td>
</tr>
</table>
</div>
<div class="section">
<div class="titlepage"><div><div>
<h3 class="title">
<a id="_renaming_files_and_directories"></a>Renaming Files and Directories<a class="edit_me edit_me_private" rel="nofollow" title="Editing on GitHub is available to Elastic" href="https://github.com/elastic/elasticsearch-definitive-guide/edit/2.x/400_Relationships/25_Concurrency.asciidoc">edit</a>
</h3>
</div></div></div>
<p>So far, so good.  Renaming a file is easy—​a simple <code class="literal">update</code> or <code class="literal">index</code>
request is all that is required.  You can even use
<a class="xref" href="optimistic-concurrency-control.html" title="Optimistic Concurrency Control">optimistic concurrency control</a> to
ensure that your change doesn’t conflict with the changes from another user:</p>
<div class="pre_wrapper lang-json">
<pre class="programlisting prettyprint lang-json">PUT /fs/file/1?version=2 <a id="CO260-1"></a><i class="conum" data-value="1"></i>
{
  "name":     "README.asciidoc",
  "path":     "/clinton/projects/elasticsearch",
  "contents": "Starting a new Elasticsearch project is easy..."
}</pre>
</div>
<div class="calloutlist">
<table border="0" summary="Callout list">
<tr>
<td align="left" valign="top" width="5%">
<p><a href="#CO260-1"><i class="conum" data-value="1"></i></a></p>
</td>
<td align="left" valign="top">
<p>The <code class="literal">version</code> number ensures that the change is applied only if the
document in the index has this same version number.</p>
</td>
</tr>
</table>
</div>
<p>We can even rename a directory, but this means updating all of the files that
exist anywhere in the path hierarchy beneath that directory.  This may be
quick or slow, depending on how many files need to be updated.  All we would
need to do is to use <a class="xref" href="scroll.html" title="Scroll"><code class="literal">scroll</code></a> to retrieve all the
files, and the <a class="xref" href="bulk.html" title="Cheaper in Bulk"><code class="literal">bulk</code> API</a> to update them.  The process isn’t
atomic, but all files will quickly move to their new home.</p>
</div>

</div>
<div class="navfooter">
<span class="prev">
<a href="top-hits.html">« Field Collapsing</a>
</span>
<span class="next">
<a href="concurrency-solutions.html">Solving Concurrency Issues »</a>
</span>
</div>
</div>

                  <!-- end body -->
                </div>
                <div class="col-xs-12 col-sm-4 col-md-4" id="right_col">
                  <div id="rtpcontainer" style="display: block;">
                    <div class="mktg-promo">
                      <h3>Most Popular</h3>
                      <ul class="icons">
                        <li class="icon-elasticsearch-white"><a href="https://www.elastic.co/webinars/getting-started-elasticsearch?baymax=default&amp;elektra=docs&amp;storm=top-video">Get Started with Elasticsearch: Video</a></li>
                        <li class="icon-kibana-white"><a href="https://www.elastic.co/webinars/getting-started-kibana?baymax=default&amp;elektra=docs&amp;storm=top-video">Intro to Kibana: Video</a></li>
                        <li class="icon-logstash-white"><a href="https://www.elastic.co/webinars/introduction-elk-stack?baymax=default&amp;elektra=docs&amp;storm=top-video">ELK for Logs &amp; Metrics: Video</a></li>
                      </ul>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </section>

        </div>


<div id="elastic-footer"></div>
<script src="https://www.elastic.co/elastic-footer.js"></script>
<!-- Footer Section end-->

      </section>
    </div>

<script src="/guide/static/jquery.js"></script>
<script type="text/javascript" src="/guide/static/docs.js"></script>
<script type="text/javascript">
  window.initial_state = {}</script>
  </body>
</html>
